﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media.Imaging;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Media.Animation;
using Bling.DSL;
using Bling.Properties;
using Bling.Animation;
using Bling.WPF;
using Bling.Shapes;
using Bling.Slides;
using Bling.Util;
using Bling.Linq;
using Bling.Lighting;
using Bling.Physics;

namespace ExpressTest {
  using System.Linq.Expressions;
  public class PresentationTestA {
    FrameworkElement wA = null, wB = null, wC = null, wD = null;
    public void F() {
      wA.Width = wB.Width + wC.Width;
      Bind(() => wA.Width, 
           () => wB.Width + wC.Width);
    }
    public void Bind(Expression<Func<double>> LHS, 
                     Expression<Func<double>> RHS) 
    { /*...*/ }

    public void G() {
      Expression<Func<double>> A0 = () => wA.Width;
      Expression<Func<double>> A1 = () => wB.Width + wC.Width;
      // how to express A0 + A1?
      // BAD: Bind(() => wD.Width, A0 + A1);
    }
    public void H() {
      DoubleBl A0 = new DoubleBl(() => wA.Width);
      DoubleBl A1 = new DoubleBl(() => wB.Width + wC.Width);
      DoubleBl A2 = new DoubleBl(() => wD.Width);
      A2.Bind = A0 + A1;
      A2.Now = A0 + A1;
      A2.AnimateTo = A0 + A1;
    }
    public class FrameworkElementBl {
      readonly FrameworkElement Un;
      public FrameworkElementBl(FrameworkElement Un) { this.Un = Un; }
      public DoubleBl Width {
        get { return new DoubleBl(() => Un.Width); }
        set { Width.Bind = value; }
      }
      public DoubleBl Left {
        get { return new DoubleBl(() => Canvas.GetLeft(Un)); }
        set { Left.Bind = value; }
      }
      public DoubleBl Right {
        get { return Width + Left; }
        set { Right.Bind = value; }
      }
    }
    public FrameworkElementBl fA, fB, fC;
    public void I() {
      fA.Right = fB.Left;
      (fA.Left + fA.Width).Bind = fB.Left;
      fA.Left = fB.Left - fA.Width;
    }

    public class DoubleBl {
      readonly Expression<Func<double>> Un;
      public DoubleBl(Expression<Func<double>> Un) { this.Un = Un; }
      public static DoubleBl operator +(DoubleBl opA, DoubleBl opB) {
        var body = Expression.Add(opA.Un.Body, opB.Un.Body);
        return Expression.Lambda<Func<double>>(body);
      }
      public static DoubleBl operator -(DoubleBl opA, DoubleBl opB) {
        var body = Expression.Subtract(opA.Un.Body, opB.Un.Body);
        return Expression.Lambda<Func<double>>(body);
      }
      public static implicit operator DoubleBl(double d) {
        return new DoubleBl(() => d);
      }
      public static implicit operator DoubleBl(Expression<Func<double>> d) { 
        return new DoubleBl(d);
      }
      public DoubleBl Bind { set { /*...*/ } }
      public DoubleBl Now { set { /* ... */ } }
      public DoubleBl AnimateTo { set { /* ... */ } }
    }
  }
}

namespace Presentation {
  public class Branding : Canvas {
    public Branding() {
      CanvasBl Canvas = this;
      var l0 = new LabelBl(Canvas) {
        CenterTop = new PointBl(Canvas.CenterSize.X, 0),
        Content = "Lightweight DSLs: Branding",
        Font = { Size = 30d, Weight = FontWeights.SemiBold, Brush = Brushes.DarkOrange },
      };

      ImageBl At;
      var all = new List<DoubleBl>();
      {
        var i0 = new ImageBl(Canvas) {
          LeftTop = new PointBl(0, l0.Bottom),
          Source = new BitmapImage("Resources/linqA.PNG".MakePackUri(typeof(Mismatch))),
          Effect = new DropShadowEffectBl(),
        };

        var i1 = new ImageBl(Canvas) {
          RightTop = new PointBl(Canvas.Width, Canvas.Height),
          ZIndex = i0.ZIndex + 1,
          Source = new BitmapImage("Resources/linqB.PNG".MakePackUri(typeof(Mismatch))),
          Effect = new DropShadowEffectBl(),
        };
        i0.OnMouseDown = (x, y) => {
          (i1.Top).Animate.Tween(d => d.Ease.Bounce.Out).To = i0.Top;
          return true;
        };
        all.Add(i1.Top);
        At = i1;
      }
      {
        var i0 = new ImageBl(Canvas) {
          LeftTop = new PointBl(0, Canvas.Height), ZIndex = At.ZIndex + 1,
          Source = new BitmapImage("Resources/brandA.PNG".MakePackUri(typeof(Mismatch))),
          Effect = new DropShadowEffectBl(),
        };
        At.OnMouseDown = (x, y) => {
          i0.Top.Animate.Tween(d => d.Ease.Bounce.Out).To = l0.Bottom;
          return true;
        };
        all.Add(i0.Top);

        var i1 = new ImageBl(Canvas) {
          RightTop = new PointBl(Canvas.Width, Canvas.Height),
          ZIndex = i0.ZIndex + 1,
          Source = new BitmapImage("Resources/brandB.PNG".MakePackUri(typeof(Mismatch))),

          Effect = new DropShadowEffectBl(),
        };
        i0.OnMouseDown = (x, y) => {
          (i1.Top).Animate.Tween(d => d.Ease.Bounce.Out).To = i0.Top;
          return true;
        };
        all.Add(i1.Top);
        At = i1;
      }
      {
        var i0 = new ImageBl(Canvas) {
          LeftTop = new PointBl(0, Canvas.Height), ZIndex = At.ZIndex + 1,
          Source = new BitmapImage("Resources/brandC.PNG".MakePackUri(typeof(Mismatch))),
          Effect = new DropShadowEffectBl(),
        };
        At.OnMouseDown = (x, y) => {
          i0.Top.Animate.Tween(d => d.Ease.Bounce.Out).To = l0.Bottom;
          return true;
        };
        all.Add(i0.Top);

        var i1 = new ImageBl(Canvas) {
          RightTop = new PointBl(Canvas.Width, Canvas.Height),
          ZIndex = i0.ZIndex + 1,
          Source = new BitmapImage("Resources/brandD.PNG".MakePackUri(typeof(Mismatch))),

          Effect = new DropShadowEffectBl(),
        };
        i0.OnMouseDown = (x, y) => {
          (i1.Top).Animate.Tween(d => d.Ease.Bounce.Out).To = i0.Top;
          return true;
        };
        all.Add(i1.Top);
        At = i1;
      }
      At.OnMouseDown = (x, y) => {
        foreach (var t in all)
          (t).Animate.Tween(d => d.Ease.Bounce.In).To = Canvas.Height;

        return true;
      };




      //Canvas.ScaleTo = this.Bl().Size * new PointBl(.95, .95);
    }
  }
  public class LayoutSlide : Canvas {
    public LayoutSlide() {
      CanvasBl Canvas = this;



      var l0 = new LabelBl(Canvas) {
        CenterTop = new PointBl(Canvas.CenterSize.X, 0),
        Content = "Layout via Databinding",
        Font = { Size = 40d, Weight = FontWeights.SemiBold, Brush = Brushes.DarkOrange },
      };
      var l1 = new LabelBl(Canvas) {
        CenterTop = new PointBl(Canvas.CenterSize.X, l0.Bottom),
        Font = { Size = 30d, Weight = FontWeights.SemiBold, Brush = Brushes.Black },
        Content = "CenterPosition = t.CenterPosition",
      };

      var slider = new SliderBl(Canvas) {
        CenterTop = new PointBl(Canvas.CenterSize.X, l1.Bottom), Width = Canvas.Width,
        Minimum = 0d, Maximum = 1d, Value = 0d,
      };
      var ToCenter = new ButtonBl(Canvas) {
        LeftTop = slider.LeftBottom, Content = "Center",
      };


      var RectCanvas = new CanvasBl(Canvas) {
        Size = new PointBl(Canvas.Width, Canvas.Height - ToCenter.Bottom),
        RightBottom = Canvas.Size,
      };

      RectangleBl[] Rects = new RectangleBl[16];
      var sz = Canvas.Size * new PointBl(.075, .075);
      sz = (sz.X < sz.Y).Condition(new PointBl(sz.X, sz.X), new PointBl(sz.Y, sz.Y));

      var thumb = new ThumbBl(RectCanvas) {
        CenterPosition = RectCanvas.CenterSize,
        CanDrag = true, Background = Brushes.Purple,
        Size = sz * new PointBl(1.2,1.2),
      };

      RectangleBl[,] Invisible = new RectangleBl[2, Rects.Length];
      for (int i = 0; i < Rects.Length; i++) {
        Rects[i] = new RectangleBl(RectCanvas) {
          Size = sz, Opacity = 1,
          Fill = i.SelectColor(), IsHitTestVisible = false,
        };
        for (int j = 0; j < 2; j++)
          Invisible[j,i] = new RectangleBl(RectCanvas) { Size = Rects[i].Size, Visibility = false, 
            CenterPosition = thumb.CenterPosition };
        var lerp = slider.Value;
        lerp = lerp.Pow(1d + ((double)i) / ((double)(Rects.Length - 1)) * 4d);

        Rects[i].LeftTop = lerp.Lerp(Invisible[0, i].LeftTop, Invisible[1, i].LeftTop);
      }

      bool state = false;
      Action<int, RectangleBl> LastA = (i,r) => { };
      Action<Action<int, RectangleBl>> Toggle = (a) => {
        //thumb.Size.Stop(false);
        //thumb.Size.Animate.Forever().AutoReverse().To = sz * new PointBl(1.1, 1.1);
        int j = !state ? 1 : 0;
        for (int i = 0; i < Rects.Length; i++) {
          LastA(i, Invisible[j, i]);
          a(i, Invisible[j, i]);
        }
        slider.Value.Animate.To = (!state) ? 1d : 0d;
        state = !state;
        LastA = a;
      };
      ToCenter.Click = () => {
        Toggle((i, r) => r.CenterPosition = thumb.CenterPosition);
        l1.Content = "CenterPosition = t.CenterPosition";
      };
      var AtButton = ToCenter;
      AtButton = new ButtonBl(Canvas) {
        LeftTop = AtButton.RightTop, Content = "LeftTop",
        Click = () => {
          Toggle((i, r) => r.LeftTop = thumb.RightBottom);
          l1.Content = "LeftTop = t.RightBottom";
        },
      };
      AtButton = new ButtonBl(Canvas) {
        LeftTop = AtButton.RightTop, Content = "Right",
        Click = () => {
          Toggle((i, r) => r.Right = thumb.Left);
          l1.Content = "Right = t.Left";
        },
      };
      AtButton = new ButtonBl(Canvas) {
        LeftTop = AtButton.RightTop, Content = "RightBottom",
        Click = () => {
          Toggle((i, r) => r.RightBottom = thumb.LeftTop);
          l1.Content = "RightBottom = t.LeftTop";
        },
      };
      AtButton = new ButtonBl(Canvas) {
        LeftTop = AtButton.RightTop, Content = "Bottom",
        Click = () => {
          Toggle((i, r) => r.Bottom = thumb.Top);
          l1.Content = "Bottom = t.Top";
        },
      };
      AtButton = new ButtonBl(Canvas) {
        LeftTop = AtButton.RightTop, Content = "Grid",
        Click = () => {
          Toggle((i, r) => r.LeftTop = new PointBl((i%4)/3d, (i/4)/3d) * (RectCanvas.Size - Rects[0].Size));
          l1.Content = "LeftTop = ((i%4)/3d, (i/4)/3d) * (Canvas.Size - Size)";
        },
      };

      AtButton = new ButtonBl(Canvas) {
        LeftTop = AtButton.RightTop, Content = "Circle",
        Click = () => {
          DoubleBl r0 = thumb.Left - Rects[0].Width;
          r0 = r0.Min(RectCanvas.Width - thumb.Right - Rects[0].Width);
          r0 = r0.Min(thumb.Top - Rects[0].Height);
          r0 = r0.Min(RectCanvas.Height - thumb.Bottom - Rects[0].Height);
          var rr = r0;

          //var sz0 = RectCanvas.Size - Rects[0].Size;
          //var rr = sz0.X.Min(sz0.Y);
          //rr = rr / 2d;

          Toggle((i, r) => r.CenterPosition = thumb.CenterPosition + 
            ((i/((double)(Rects.Length))) * 2d).ToPI().ToPoint() * rr);
          l1.Content = "CenterPosition = t.CenterPosition + a(i).ToPoint() * rr";
        },
      };
    }
  }


}
